﻿using System;
using System.Threading.Tasks;
using Netbits.Common.Extensions;

namespace Netbits.Common.Threading
{
	#region Event without parameters

	/// <summary>
	/// Represent a thread-safe event handler.
	/// </summary>
	public sealed class SaveEventHandler<TSender> : IDisposable
	{
		#region Private Variables

		/// <summary>
		/// The Lock instance. Only used on Mono runtime.
		/// </summary>
		readonly Lock _Lock;
		/// <summary>
		/// The Event Handler.
		/// </summary>
		event Action<TSender> _Handler = null;
		/// <summary>
		/// Should the handler called asynchronous.
		/// </summary>
		int _UseAsyncCallback = 0;

		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Default Constructor
		/// Create a new LockedEvent instance with 
		///		synchronous event handling and
		///		on MONO with new Lock instance.
		/// </summary>
		public SaveEventHandler() : this( 0, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with 
		///		specified event handling (0=synchronous, >0=asynchronous)
		///		on MONO with new Lock instance.
		/// </summary>
		/// <param name="UseAsyncCallback_">if greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		public SaveEventHandler( int UseAsyncCallback_ ) : this( UseAsyncCallback_, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		synchronous event handling and
		///		specified Lock-instance.
		/// </summary>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( Lock Lock_ ) : this( 0, Lock_ )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		specified event handling (0=synchronous, >0=asynchronous) and with
		///		specified Lock-instance (only used on MONO runtime)
		/// </summary>
		/// <param name="UseAsyncCallback_">If greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( int UseAsyncCallback_, Lock Lock_ )
		{
			// Only on MONO we need an extra lock
			if( EnvironmentExtensions.IsMonoRuntime )
				_Lock = Lock_;

			_UseAsyncCallback = UseAsyncCallback_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the if asynchronous event-handling is activated.
		///		0  = synchronous event-handling
		///		>0 = asynchronous event-handling
		/// </summary>
		public int UseAsyncCallback
		{
			get
			{
				return _UseAsyncCallback;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _UseAsyncCallback, value );
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Join this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that add to the EventHandler</param>
		/// <remarks>The object parameter is the sender of this event</remarks>
		public void Join( Action<TSender> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler += Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Leave this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that remove from the EventHandler</param>
		public void Leave( Action<TSender> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler -= Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Fire the notification
		/// </summary>
		/// <param name="Sender_">The sender of this event.</param>
		public void Notify( TSender Sender_ )
		{
			Action<TSender> eh = null;

			if( EnvironmentExtensions.IsMonoRuntime )
			{
				try
				{
					_Lock.EnterReadLock();
					eh = _Handler;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			else
				eh = _Handler;

			if( eh == null )
				return;

			if( _UseAsyncCallback > 0 )
				TaskHelper.Run( _NotifyHandler, eh, Sender_ );
			else
				_NotifyHandler( eh, Sender_ );
		}

		#endregion

		#region Private Functions

		void _NotifyHandler( Action<TSender> Handler_, TSender Sender_ )
		{
			foreach( Action<TSender> handler in Handler_.GetInvocationList() )
			{
				try
				{
					handler( Sender_ );
				}
#if DEBUG
				catch( Exception Ex_ )
				{
					Console.WriteLine( Ex_ );
				}
#endif
				finally
				{
				}
			}
		}

		void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( Disposing_ )
				{
					if( _Lock != null )
						_Lock.Dispose();
				}
				_Disposed = true;
			}
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Dispose SaveEventhHandler Resources
		/// </summary>
		public void Dispose()
		{
			Dispose( true );
			GC.SuppressFinalize( this );
		}

		#endregion
	}

	#endregion

	#region Event with one parameter

	/// <summary>
	/// Represent a thread-safe event handler.
	/// </summary>
	public sealed class SaveEventHandler<TSender, TParam> : IDisposable
	{
		#region Private Variables

		/// <summary>
		/// The Lock instance. Only used on Mono runtime.
		/// </summary>
		readonly Lock _Lock;
		/// <summary>
		/// The Event Handler.
		/// </summary>
		event Action<TSender, TParam> _Handler = null;
		/// <summary>
		/// Should the handler called asynchronous.
		/// </summary>
		int _UseAsyncCallback = 0;

		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Default Constructor
		/// Create a new LockedEvent instance with 
		///		synchronous event handling and
		///		on MONO with new Lock instance.
		/// </summary>
		public SaveEventHandler()
			: this( 0, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with 
		///		specified event handling (0=synchronous, >0=asynchronous)
		///		on MONO with new Lock instance.
		/// </summary>
		/// <param name="UseAsyncCallback_">if greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		public SaveEventHandler( int UseAsyncCallback_ )
			: this( UseAsyncCallback_, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		synchronous event handling and
		///		specified Lock-instance.
		/// </summary>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( Lock Lock_ )
			: this( 0, Lock_ )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		specified event handling (0=synchronous, >0=asynchronous) and with
		///		specified Lock-instance (only used on MONO runtime)
		/// </summary>
		/// <param name="UseAsyncCallback_">If greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( int UseAsyncCallback_, Lock Lock_ )
		{
			// Only on MONO we need an extra lock
			if( EnvironmentExtensions.IsMonoRuntime )
				_Lock = Lock_;

			_UseAsyncCallback = UseAsyncCallback_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the if asynchronous event-handling is activated.
		///		0  = synchronous event-handling
		///		>0 = asynchronous event-handling
		/// </summary>
		public int UseAsyncCallback
		{
			get
			{
				return _UseAsyncCallback;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _UseAsyncCallback, value );
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Join this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that add to the EventHandler</param>
		/// <remarks>The object parameter is the sender of this event</remarks>
		public void Join( Action<TSender, TParam> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler += Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Leave this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that remove from the EventHandler</param>
		public void Leave( Action<TSender, TParam> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler -= Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Fire the notification
		/// </summary>
		/// <param name="Sender_">The sender of this event.</param>
		/// <param name="Parameter_">The parameter</param>
		public void Notify( TSender Sender_, TParam Parameter_ )
		{
			Action<TSender, TParam> eh = null;

			if( EnvironmentExtensions.IsMonoRuntime )
			{
				try
				{
					_Lock.EnterReadLock();
					eh = _Handler;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			else
				eh = _Handler;

			if( eh == null )
				return;

			if( _UseAsyncCallback > 0 )
				TaskHelper.Run( _NotifyHandler, eh, Sender_, Parameter_ );
			else
				_NotifyHandler( eh, Sender_, Parameter_ );
		}

		#endregion

		#region Private Functions

		void _NotifyHandler( Action<TSender, TParam> Handler_, TSender Sender_, TParam Parameter_ )
		{
			foreach( Action<TSender, TParam> handler in Handler_.GetInvocationList() )
			{
				try
				{
					handler( Sender_, Parameter_ );
				}
#if DEBUG
				catch( Exception Ex_ )
				{
					Console.WriteLine( Ex_ );
				}
#endif
				finally
				{
				}
			}
		}

		#endregion

		#region IDisposable

		void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( Disposing_ )
				{
					if( _Lock != null )
						_Lock.Dispose();
				}

				_Disposed = true;
			}
		}

		/// <summary>
		/// Dispose SaveEventhHandler Resources
		/// </summary>
		public void Dispose()
		{
			Dispose( true );
			GC.SuppressFinalize( this );
		}

		#endregion
	}

	#endregion

	#region Event with two parameters

	/// <summary>
	/// Represent a thread-safe event handler.
	/// </summary>
	public sealed class SaveEventHandler<TSender, TParam1, TParam2> : IDisposable
	{
		#region Private Variables

		/// <summary>
		/// The Lock instance. Only used on Mono runtime.
		/// </summary>
		Lock _Lock;
		/// <summary>
		/// The Event Handler.
		/// </summary>
		event Action<TSender, TParam1, TParam2> _Handler = null;
		/// <summary>
		/// Should the handler called asynchronous.
		/// </summary>
		int _UseAsyncCallback = 0;

		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Default Constructor
		/// Create a new LockedEvent instance with 
		///		synchronous event handling and
		///		on MONO with new Lock instance.
		/// </summary>
		public SaveEventHandler()
			: this( 0, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with 
		///		specified event handling (0=synchronous, >0=asynchronous)
		///		on MONO with new Lock instance.
		/// </summary>
		/// <param name="UseAsyncCallback_">if greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		public SaveEventHandler( int UseAsyncCallback_ )
			: this( UseAsyncCallback_, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		synchronous event handling and
		///		specified Lock-instance.
		/// </summary>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( Lock Lock_ )
			: this( 0, Lock_ )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		specified event handling (0=synchronous, >0=asynchronous) and with
		///		specified Lock-instance (only used on MONO runtime)
		/// </summary>
		/// <param name="UseAsyncCallback_">If greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( int UseAsyncCallback_, Lock Lock_ )
		{
			// Only on MONO we need an extra lock
			if( EnvironmentExtensions.IsMonoRuntime )
				_Lock = Lock_;

			_UseAsyncCallback = UseAsyncCallback_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the if asynchronous event-handling is activated.
		///		0  = synchronous event-handling
		///		>0 = asynchronous event-handling
		/// </summary>
		public int UseAsyncCallback
		{
			get
			{
				return _UseAsyncCallback;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _UseAsyncCallback, value );
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Join this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that add to the EventHandler</param>
		/// <remarks>The object parameter is the sender of this event</remarks>
		public void Join( Action<TSender, TParam1, TParam2> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler += Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Leave this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that remove from the EventHandler</param>
		public void Leave( Action<TSender, TParam1, TParam2> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler -= Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Fire the notification
		/// </summary>
		/// <param name="Sender_">The sender of this event.</param>
		/// <param name="Parameter1_">The first parameter</param>
		/// <param name="Parameter2_">The second parameter</param>
		public void Notify( TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_ )
		{
			Action<TSender, TParam1, TParam2> eh = null;

			if( EnvironmentExtensions.IsMonoRuntime )
			{
				try
				{
					_Lock.EnterReadLock();
					eh = _Handler;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			else
				eh = _Handler;

			if( eh == null )
				return;

			if( _UseAsyncCallback > 0 )
				TaskHelper.Run( _NotifyHandler, eh, Sender_, Parameter1_, Parameter2_ );
			else
				_NotifyHandler( eh, Sender_, Parameter1_, Parameter2_ );
		}

		#endregion

		#region Private Functions

		void _NotifyHandler( Action<TSender, TParam1, TParam2> Handler_, TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_ )
		{
			foreach( Action<TSender, TParam1, TParam2> handler in Handler_.GetInvocationList() )
			{
				try
				{
					handler( Sender_, Parameter1_, Parameter2_ );
				}
#if DEBUG
				catch( Exception Ex_ )
				{
					Console.WriteLine( Ex_ );
				}
#endif
				finally
				{
				}
			}
		}

		void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( Disposing_ )
				{
					if( _Lock != null )
						_Lock.Dispose();
				}
				_Disposed = true;
			}
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Dispose SaveEventhHandler Resources
		/// </summary>
		public void Dispose()
		{
			Dispose( true );
			GC.SuppressFinalize( this );
		}

		#endregion
	}

	#endregion

	#region Event with three parameters

	/// <summary>
	/// Represent a thread-safe event handler.
	/// </summary>
	public sealed class SaveEventHandler<TSender, TParam1, TParam2, TParam3> : IDisposable
	{
		#region Private Variables

		/// <summary>
		/// The Lock instance. Only used on Mono runtime.
		/// </summary>
		readonly Lock _Lock;
		/// <summary>
		/// The Event Handler.
		/// </summary>
		event Action<TSender, TParam1, TParam2, TParam3> _Handler = null;
		/// <summary>
		/// Should the handler called asynchronous.
		/// </summary>
		int _UseAsyncCallback = 0;

		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Default Constructor
		/// Create a new LockedEvent instance with 
		///		synchronous event handling and
		///		on MONO with new Lock instance.
		/// </summary>
		public SaveEventHandler()
			: this( 0, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with 
		///		specified event handling (0=synchronous, >0=asynchronous)
		///		on MONO with new Lock instance.
		/// </summary>
		/// <param name="UseAsyncCallback_">if greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		public SaveEventHandler( int UseAsyncCallback_ )
			: this( UseAsyncCallback_, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		synchronous event handling and
		///		specified Lock-instance.
		/// </summary>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( Lock Lock_ )
			: this( 0, Lock_ )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		specified event handling (0=synchronous, >0=asynchronous) and with
		///		specified Lock-instance (only used on MONO runtime)
		/// </summary>
		/// <param name="UseAsyncCallback_">If greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( int UseAsyncCallback_, Lock Lock_ )
		{
			// Only on MONO we need an extra lock
			if( EnvironmentExtensions.IsMonoRuntime )
				_Lock = Lock_;

			_UseAsyncCallback = UseAsyncCallback_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the if asynchronous event-handling is activated.
		///		0  = synchronous event-handling
		///		>0 = asynchronous event-handling
		/// </summary>
		public int UseAsyncCallback
		{
			get
			{
				return _UseAsyncCallback;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _UseAsyncCallback, value );
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Join this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that add to the EventHandler</param>
		/// <remarks>The object parameter is the sender of this event</remarks>
		public void Join( Action<TSender, TParam1, TParam2, TParam3> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler += Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Leave this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that remove from the EventHandler</param>
		public void Leave( Action<TSender, TParam1, TParam2, TParam3> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler -= Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Fire the notification
		/// </summary>
		/// <param name="Sender_">The sender of this event.</param>
		/// <param name="Parameter1_">The first parameter</param>
		/// <param name="Parameter2_">The second parameter</param>
		/// <param name="Parameter3_">The third parameter</param>
		public void Notify( TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_, TParam3 Parameter3_ )
		{
			Action<TSender, TParam1, TParam2, TParam3> eh = null;

			if( EnvironmentExtensions.IsMonoRuntime )
			{
				try
				{
					_Lock.EnterReadLock();
					eh = _Handler;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			else
				eh = _Handler;

			if( eh == null )
				return;

			if( _UseAsyncCallback > 0 )
				TaskHelper.Run( _NotifyHandler, eh, Sender_, Parameter1_, Parameter2_, Parameter3_ );
			else
				_NotifyHandler( eh, Sender_, Parameter1_, Parameter2_, Parameter3_ );
		}

		#endregion

		#region Private Functions

		void _NotifyHandler( Action<TSender, TParam1, TParam2, TParam3> Handler_, TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_, TParam3 Parameter3_ )
		{
			foreach( Action<TSender, TParam1, TParam2, TParam3> handler in Handler_.GetInvocationList() )
			{
				try
				{
					handler( Sender_, Parameter1_, Parameter2_, Parameter3_ );
				}
#if DEBUG
				catch( Exception Ex_ )
				{
					Console.WriteLine( Ex_ );
				}
#endif
				finally
				{
				}
			}
		}

		void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( Disposing_ )
				{
					if( _Lock != null )
						_Lock.Dispose();
				}
				_Disposed = true;
			}
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Dispose SaveEventhHandler Resources
		/// </summary>
		public void Dispose()
		{
			Dispose( true );
			GC.SuppressFinalize( this );
		}

		#endregion
	}

	#endregion

	#region Event with four parameters

	/// <summary>
	/// Represent a thread-safe event handler.
	/// </summary>
	public sealed class SaveEventHandler<TSender, TParam1, TParam2, TParam3, TParam4> : IDisposable
	{
		#region Private Variables

		/// <summary>
		/// The Lock instance. Only used on Mono runtime.
		/// </summary>
		readonly Lock _Lock;
		/// <summary>
		/// The Event Handler.
		/// </summary>
		event Action<TSender, TParam1, TParam2, TParam3, TParam4> _Handler = null;
		/// <summary>
		/// Should the handler called asynchronous.
		/// </summary>
		int _UseAsyncCallback = 0;

		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Default Constructor
		/// Create a new LockedEvent instance with 
		///		synchronous event handling and
		///		on MONO with new Lock instance.
		/// </summary>
		public SaveEventHandler()
			: this( 0, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with 
		///		specified event handling (0=synchronous, >0=asynchronous)
		///		on MONO with new Lock instance.
		/// </summary>
		/// <param name="UseAsyncCallback_">if greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		public SaveEventHandler( int UseAsyncCallback_ )
			: this( UseAsyncCallback_, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		synchronous event handling and
		///		specified Lock-instance.
		/// </summary>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( Lock Lock_ )
			: this( 0, Lock_ )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		specified event handling (0=synchronous, >0=asynchronous) and with
		///		specified Lock-instance (only used on MONO runtime)
		/// </summary>
		/// <param name="UseAsyncCallback_">If greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( int UseAsyncCallback_, Lock Lock_ )
		{
			// Only on MONO we need an extra lock
			if( EnvironmentExtensions.IsMonoRuntime )
				_Lock = Lock_;

			_UseAsyncCallback = UseAsyncCallback_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the if asynchronous event-handling is activated.
		///		0  = synchronous event-handling
		///		>0 = asynchronous event-handling
		/// </summary>
		public int UseAsyncCallback
		{
			get
			{
				return _UseAsyncCallback;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _UseAsyncCallback, value );
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Join this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that add to the EventHandler</param>
		/// <remarks>The object parameter is the sender of this event</remarks>
		public void Join( Action<TSender, TParam1, TParam2, TParam3, TParam4> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler += Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Leave this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that remove from the EventHandler</param>
		public void Leave( Action<TSender, TParam1, TParam2, TParam3, TParam4> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler -= Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Fire the notification
		/// </summary>
		/// <param name="Sender_">The sender of this event.</param>
		/// <param name="Parameter1_">The first parameter</param>
		/// <param name="Parameter2_">The second parameter</param>
		/// <param name="Parameter3_">The fired parameter</param>
		/// <param name="Parameter4_">The fifth parameter</param>
		public void Notify( TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_, TParam3 Parameter3_, TParam4 Parameter4_ )
		{
			Action<TSender, TParam1, TParam2, TParam3, TParam4> eh = null;

			if( EnvironmentExtensions.IsMonoRuntime )
			{
				try
				{
					_Lock.EnterReadLock();
					eh = _Handler;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			else
				eh = _Handler;

			if( eh == null )
				return;

			if( _UseAsyncCallback > 0 )
				TaskHelper.Run( _NotifyHandler, eh, Sender_, Parameter1_, Parameter2_, Parameter3_, Parameter4_ );
			else
				_NotifyHandler( eh, Sender_, Parameter1_, Parameter2_, Parameter3_, Parameter4_ );
		}

		#endregion

		#region Private Functions

		void _NotifyHandler( Action<TSender, TParam1, TParam2, TParam3, TParam4> Handler_, TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_, TParam3 Parameter3_, TParam4 Parameter4_ )
		{
			foreach( Action<object, TParam1, TParam2, TParam3, TParam4> handler in Handler_.GetInvocationList() )
			{
				try
				{
					handler( Sender_, Parameter1_, Parameter2_, Parameter3_, Parameter4_ );
				}
#if DEBUG
				catch( Exception Ex_ )
				{
					Console.WriteLine( Ex_ );
				}
#endif
				finally
				{
				}
			}
		}

		void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( Disposing_ )
				{
					if( _Lock != null )
						_Lock.Dispose();
				}

				_Disposed = true;
			}
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Dispose SaveEventhHandler Resources
		/// </summary>
		public void Dispose()
		{
			Dispose( true );
			GC.SuppressFinalize( this );
		}

		#endregion
	}

	#endregion

	#region Event with five parameters

	/// <summary>
	/// Represent a thread-safe event handler.
	/// </summary>
	public sealed class SaveEventHandler<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> : IDisposable
	{
		#region Private Variables

		/// <summary>
		/// The Lock instance. Only used on Mono runtime.
		/// </summary>
		readonly Lock _Lock;
		/// <summary>
		/// The Event Handler.
		/// </summary>
		event Action<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> _Handler = null;
		/// <summary>
		/// Should the handler called asynchronous.
		/// </summary>
		int _UseAsyncCallback = 0;

		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Default Constructor
		/// Create a new LockedEvent instance with 
		///		synchronous event handling and
		///		on MONO with new Lock instance.
		/// </summary>
		public SaveEventHandler()
			: this( 0, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with 
		///		specified event handling (0=synchronous, >0=asynchronous)
		///		on MONO with new Lock instance.
		/// </summary>
		/// <param name="UseAsyncCallback_">if greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		public SaveEventHandler( int UseAsyncCallback_ )
			: this( UseAsyncCallback_, new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		synchronous event handling and
		///		specified Lock-instance.
		/// </summary>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( Lock Lock_ )
			: this( 0, Lock_ )
		{
		}

		/// <summary>
		/// Create a new instance of LockedEvent with
		///		specified event handling (0=synchronous, >0=asynchronous) and with
		///		specified Lock-instance (only used on MONO runtime)
		/// </summary>
		/// <param name="UseAsyncCallback_">If greater than 0 asynchronous handling is activated, otherwise synchronous events are used</param>
		/// <param name="Lock_">The Lock instance to use</param>
		public SaveEventHandler( int UseAsyncCallback_, Lock Lock_ )
		{
			// Only on MONO we need an extra lock
			if( EnvironmentExtensions.IsMonoRuntime )
				_Lock = Lock_;

			_UseAsyncCallback = UseAsyncCallback_;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the if asynchronous event-handling is activated.
		///		0  = synchronous event-handling
		///		>0 = asynchronous event-handling
		/// </summary>
		public int UseAsyncCallback
		{
			get
			{
				return _UseAsyncCallback;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _UseAsyncCallback, value );
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Join this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that add to the EventHandler</param>
		/// <remarks>The object parameter is the sender of this event</remarks>
		public void Join( Action<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler += Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Leave this event-handler with specified handler.
		/// </summary>
		/// <param name="Handler_">Function that remove from the EventHandler</param>
		public void Leave( Action<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> Handler_ )
		{
			try
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.EnterWriteLock();

				_Handler -= Handler_;
			}
			finally
			{
				if( EnvironmentExtensions.IsMonoRuntime )
					_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Fire the notification
		/// </summary>
		/// <param name="Sender_">The sender of this event.</param>
		/// <param name="Parameter1_">The first parameter</param>
		/// <param name="Parameter2_">The second parameter</param>
		/// <param name="Parameter3_">The fired parameter</param>
		/// <param name="Parameter4_">The fourth parameter</param>
		/// <param name="Parameter5_">The fifth parameter</param>
		public void Notify( TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_, TParam3 Parameter3_, TParam4 Parameter4_, TParam5 Parameter5_ )
		{
			Action<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> eh = null;

			if( EnvironmentExtensions.IsMonoRuntime )
			{
				try
				{
					_Lock.EnterReadLock();
					eh = _Handler;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			else
				eh = _Handler;

			if( eh == null )
				return;

			if( _UseAsyncCallback > 0 )
				TaskHelper.Run( _NotifyHandler, eh, Sender_, Parameter1_, Parameter2_, Parameter3_, Parameter4_, Parameter5_ );
			else
				_NotifyHandler( eh, Sender_, Parameter1_, Parameter2_, Parameter3_, Parameter4_, Parameter5_ );
		}

		#endregion

		#region Private Functions

		void _NotifyHandler( Action<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> Handler_, TSender Sender_, TParam1 Parameter1_, TParam2 Parameter2_, TParam3 Parameter3_, TParam4 Parameter4_, TParam5 Parameter5_ )
		{
			foreach( Action<TSender, TParam1, TParam2, TParam3, TParam4, TParam5> handler in Handler_.GetInvocationList() )
			{
				try
				{
					handler( Sender_, Parameter1_, Parameter2_, Parameter3_, Parameter4_, Parameter5_ );
				}
#if DEBUG
				catch( Exception Ex_ )
				{
					Console.WriteLine( Ex_ );
				}
#endif
				finally
				{
				}
			}
		}

		void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( Disposing_ )
				{
					if( _Lock != null )
						_Lock.Dispose();
				}
				_Disposed = true;
			}
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Dispose SaveEventhHandler Resources
		/// </summary>
		public void Dispose()
		{
			Dispose( true );
			GC.SuppressFinalize( this );
		}

		#endregion
	}

	#endregion
}
